﻿using Google.Protobuf.Collections;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OpenCvApplication.View
{
    public partial class FrmhuffmanCode : Form
    {
        private Bitmap _img;
        public FrmhuffmanCode(Bitmap bitmap)
        {
            InitializeComponent();
            _img = bitmap;
        }

        private unsafe void FrmhuffmanCode_Load(object sender, EventArgs e)
        {
            Rectangle rectangle = new Rectangle(0, 0, _img.Width, _img.Height);
            BitmapData bitmapData = _img.LockBits(rectangle, ImageLockMode.ReadWrite, _img.PixelFormat);
            byte* ptr = (byte*)bitmapData.Scan0;
            // 直方图数组
            float[] hist = new float[256];
            float[] feq = new float[256];
            float[] hMap = new float[256];
            string[] strCode= new string[256];
            float entr = 0f;
            float codeLeng = 0f;
            int bytes = _img.Width * _img.Height;
            fixed (float* hist2 = hist, hMap2 = hMap,feq2=feq)
            {
                // 赋初值
                for (int i = 0; i < hist.Length; i++)
                {
                    *(hist2 + i) = 0f;
                    *(hMap2+i) = i;
                }

                // 计算图像的直方图
                int str = bitmapData.Stride - bitmapData.Width * 3;
                byte temp;
                for (int y = 0; y < bitmapData.Height; y++)
                {
                    for (int x = 0; x < bitmapData.Width; x++)
                    {
                        temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                       *(hist2 + temp) += 1;
                        ptr += 3;
                    }
                    // 指向下一行数组的首个字符
                    ptr += str;
                }

                // 计算图像灰度值的出现概率
                for (int i = 0; i < hist.Length; i++)
                {
                    *(hist2 + i) /= bytes;
                    *(feq2 + i) = *(hist2 + i);
                }

                // 排序，并记录映射关系
                float tmp;
                for (int i = 0; i < 255; i++)
                {
                    for (int j = 0; j < 255 - i; j++)
                    {
                        if (*(hist2 + j) > *(hist2 + j + 1))
                        {
                            tmp = *(hist2 + j);
                            *(hist2 + j) = *(hist2 + j + 1);
                            *(hist2 + j+1)=tmp;
                            for (int k = 0; k < 256; k++)
                            {
                                if (*(hMap2 + k) == j)
                                    *(hMap2 + k) = j + 1;
                                else if (*(hMap2 + k) == j + 1)
                                    *(hMap2 + k) = j;
                            }
                        }
                    }
                }

                // 哈夫曼编码
                for (int i = 0; i < 255; i++)
                {
                    if (*(hist2 + i) == 0f) continue;
                    for (int j = 0; j < 255; j++)
                    {
                        for (int k = 0; k < 256; k++)
                        {
                            if (*(hMap2 + k) == j)
                                strCode[k] = "1" + strCode[k];
                            else if (*(hMap2 + k) == j + 1)
                                strCode[k] = "0" + strCode[k];
                        }
                        // 合并最小的两个概率值
                        *(hist2 + j + 1) += *(hist2 + j);
                        // 更新映射关系
                        for (int k = 0; k < 256; k++)
                        {
                            if (*(hMap2 + k) == j)
                                *(hMap2 + k) = j + 1;
                        }
                        // 对余下的概率再重新进行排序
                        for (int m = j + 1; m < 255; m++)
                        {
                            if (*(hist2 + m) > *(hist2 + 1 + m))
                            {
                                tmp = *(hist2 + m);
                                *(hist2 + m) = *(hist2 + m + 1);
                                *(hist2 + m + 1) = tmp;
                                for (int k = 0; k < 256; k++)
                                {
                                    if (*(hMap2 + k) == m)
                                        *(hMap2 + k) = m + 1;
                                    else if (*(hMap2 + k) == m + 1)
                                        *(hMap2 + k) = m;
                                }
                            }
                            else
                                break;
                        }
                    }
                    break;
                }
            }
            


            _img.UnlockBits(bitmapData);
        }

        public byte[] CompressWithHuffman(byte[] data)
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress))
                {
                    deflateStream.Write(data, 0, data.Length);
                }

                return memoryStream.ToArray();
            }
        }
    }
}
